#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import os
import re

from common.common import execute_cmd
from common.const import CMDResult
from common.file_common import change_path_permission
from common.util.cmd_utils import cmd_format
from common.util.exec_utils import exec_overwrite_file
from gaussdbt.single import LOGGER
from gaussdbt.single.comm.utils.gst_single_comm_utils import GstSingleCommonUtil


class GstZbackupUtil:
    @staticmethod
    def get_database_version(os_user, gsdb_home):
        """备份时获取数据库版本信息"""
        cmd_path = os.path.join(gsdb_home, "bin", "zengine")
        GstSingleCommonUtil.check_params(check_users=[os_user], check_path_owners=[(cmd_path, [os_user])])
        version_cmd = cmd_format("{} -v", cmd_path)
        cmd = f'su - {os_user} -c "{version_cmd}"'
        ret, out, err = execute_cmd(cmd)
        if ret != CMDResult.SUCCESS.value:
            LOGGER.error("Get database version failed, code: %s, out: %s, err: %s.", ret, out, err)
            return ''
        return str(out).strip()

    @staticmethod
    def record_zip_info(os_user, back_dir, back_info):
        """
        记录backup_zip_info
        """
        file_path = os.path.join(back_dir, "backup_zip_info")
        zip_mode = "ZIP_MODE=%s" % back_info.get("ZIP_MODE", "")
        time_delta = "TIME_DELTA=%s" % back_info.get("TIME_DELTA", "0:0")
        zip_level = "ZIP_LEVEL=%s" % back_info.get("ZIP_LEVEL", "")
        parallel_num = "PARALLEL_NUM=%s" % back_info.get("PARALLEL_NUM", "")
        db_version = "DB_VERSION=%s" % back_info.get("DB_VERSION", "")
        data = f"{zip_mode}{os.linesep}{time_delta}{os.linesep}{zip_level}{os.linesep}{parallel_num}{os.linesep}" \
               f"{db_version}{os.linesep} "
        exec_overwrite_file(file_path, data, json_flag=False)
        change_path_permission(file_path, os_user)

    @staticmethod
    def handle_backup_sed_issue(os_user, out_msg, back_dir=None, gsdb_home=None, gsdb_data=None):
        """处理备份时sed错误"""
        if "Error: failed replace the absolute path of tablespace with relative path." not in out_msg:
            return False
        if any([back_dir is None, gsdb_home is None, gsdb_data is None]):
            LOGGER.error("The back_dir(%s) or gsdb_home(%s) is empty.", back_dir, gsdb_home)
            return False
        search_ret = re.search(r'/(sed.+): Operation not permitted', out_msg)
        if not search_ret:
            return False
        # 修改metadata_TBS_USERS.tmp中的备份目录信息
        meta_file = os.path.join(back_dir, "metadata_TBS_USERS.tmp")
        if not os.path.isfile(meta_file):
            return False
        with open(meta_file, mode='r', encoding='utf-8') as m_file:
            all_lines = m_file.readlines()
        with open(meta_file, mode='w', encoding='utf-8') as m_file:
            for line in all_lines:
                if gsdb_data in line:
                    line = line.replace(gsdb_data, '?')
                m_file.write(line)
        # 记录backup_zip_info信息
        db_version = GstZbackupUtil.get_database_version(os_user, gsdb_home)
        back_info = {
            "DB_VERSION": db_version
        }
        GstZbackupUtil.record_zip_info(os_user, back_dir, back_info)
        LOGGER.info("Handle backup sed issue success.")
        return True
